home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / DVIM72-Mac 1.9.6 / source / TextDisplay.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-14  |  13.5 KB  |  480 lines  |  [TEXT/R*ch]

  1. #include <string.h>
  2. #include <stdarg.h>
  3. #include <stdio.h>
  4.  
  5. #define TD_COPYABLE        0    /* Allow selecting and copying of text. */
  6.  
  7. #include "TextDisplay.h"
  8. #include "mac-specific.h"
  9. char **
  10.         get_str_resource( char *rsrc_name );
  11.  
  12. /* =====================================================================
  13.     TextDisplay provides a window for the display of non-editable text.
  14. The idea is similar to THINK C's console window, except that TextDisplay
  15. windows are scrollable.  The console window also takes care of more stuff
  16. behind your back, which can be good for quick and dirty projects but can
  17. get in the way once you start to learn the toolbox.
  18.  
  19. Call TD_new once to create a TextDisplay window.  It returns a WindowPtr,
  20. which you can use like any other WindowPtr.  The window it returns is
  21. initially hidden, giving you a chance to move it or resize it before
  22. showing it, but you must remember to show it with ShowWindow.
  23.  
  24. Call TD_activate on every activate/deactivate or suspend/resume event,
  25. with a second parameter of TRUE or FALSE according to whether the window
  26. is activating.  You don't need to check whether the event is for the
  27. TextDisplay window or some other window, TD_activate checks that.  You
  28. should do a SetPort to the window being activated/deactivated before
  29. calling TD_activate, however.
  30.  
  31. For best results, also call TD_activate (with second parameter FALSE)
  32. before showing a modal dialog or alert.
  33.  
  34. Call TD_update whenever you handle an update event.
  35.  
  36. Call TD_click when you receive a mousedown event in the content region of
  37. the front window.  This is for scrolling and selection.
  38.  
  39. Call TD_resize after you grow or zoom a window.
  40.  
  41. Call TD_copy when "Copy" is selected from the Edit menu.
  42.  
  43. Finally, TD_printf actually puts text in the window.  Its first parameter
  44. is a pointer to a TextDisplay window, and its other parameters are
  45. those of printf.
  46.  
  47. In this sample, the TextDisplay window uses a custom WDEF for a movable,
  48. resizable window without a title bar.  You could use an ordinary window,
  49. but then you would have to be careful about how you draw the grow icon.
  50. My custom WDEF has the unusual feature that the grow region is part of the
  51. window frame, so it is always drawn automatically.
  52. ======================================================================= */
  53.  
  54. /* ------------------- global variables ------------------------------ */
  55. short    g_logfile_refnum;
  56. short    g_app_wdrefnum;    /* working directory ref num */
  57.  
  58. /* ----------------- Prototypes of private routines ------------------ */
  59. #if !TD_COPYABLE
  60. void    High_hook( void );    /* Prevents selection from being hilited */
  61. #endif
  62. static void    TD_adjust_scrollbar_max( TEHandle the_text,
  63.                                     ControlHandle the_bar );
  64. static void    Adjust_text( TEHandle the_text, ControlHandle the_bar );
  65. static pascal void Scroll_text( ControlHandle what, int part_code );
  66. static void    Handle_scroll( TEHandle the_text, int the_part, Point where,
  67.             ControlHandle scrollbar );
  68. static pascal    Boolean Auto_scroll( void );
  69.  
  70.  
  71. /* ------------------------- TD_new ----------------------------- */
  72. WindowPtr TD_new(
  73.     int        window_id,        /* ID of WIND resource */
  74.     int        max_text,        /* keep at most this many characters */
  75.     int        min_text,        /* don't discard any text before this */
  76.     int        text_size,        /* font size */
  77.     OSErr    *status )        /* error code */
  78. {
  79.     WindowPtr    the_window;
  80.     Handle        a_handle;
  81.     Rect        dest_rect, view_rect;
  82.     TEHandle    text_h;
  83.     ControlHandle    the_bar;
  84.     Ptr            window_storage;
  85.     OSErr        err;
  86.     char        **t_str;
  87.     char        message[80];
  88.     Str255        volname;
  89.     
  90.     
  91.     /* Enough memory? */
  92.     if (max_text > MaxBlock())
  93.     {
  94.         *status = memFullErr;
  95.         return nil;
  96.     }
  97.     
  98.     /* First, get a window. */
  99.     a_handle = GetResource( 'WIND', window_id );
  100.     if ( (ResError() != noErr) || (a_handle == nil) )
  101.     {
  102.         *status = ResError();
  103.         return nil;
  104.     }
  105.     window_storage = NewPtr( sizeof(TD_record) );
  106.     if (MemError() != noErr)
  107.     {
  108.         *status = MemError();
  109.         return nil;        
  110.     }
  111.     the_window = GetNewWindow( window_id, window_storage, (WindowPtr)-1L );
  112.     SetPort( the_window );
  113.     TextSize( text_size );
  114.     
  115.     ((TD_peek)the_window)->max_text = max_text;
  116.     ((TD_peek)the_window)->min_text = min_text;
  117.     
  118.     /* Get a TE record. */
  119.     dest_rect = view_rect = the_window->portRect; /* Adjust later */
  120.     ((TD_peek)the_window)->text = text_h = TENew( &dest_rect, &view_rect );
  121. #if TD_COPYABLE
  122.     (**text_h).highHook = nil;
  123. #else
  124.     (**text_h).highHook = (ProcPtr)High_hook;
  125. #endif
  126.     
  127.     /* Make a scroll bar. */
  128.     the_bar = NewControl( the_window, &dest_rect, "\p", FALSE,
  129.         0, 0, 0, scrollBarProc, 0L );
  130.     g_console_window = the_window;
  131.     TD_resize();
  132.     
  133.     TEAutoView( TRUE, text_h );    /* Permit auto-scrolling */
  134.     SetClikLoop( (ProcPtr)Auto_scroll, text_h );
  135.     ShowControl( the_bar );
  136.     
  137.     t_str = get_str_resource( "CONSOLE_LOG_FILE" );
  138.     HLock( t_str );
  139.     (void) CtoPstr( *t_str );
  140.     (void)    GetVol( volname, &g_app_wdrefnum );
  141.     err = FSDelete( (StringPtr)*t_str, g_app_wdrefnum );
  142.     if ( (err != noErr) && (err != fnfErr) )
  143.     {
  144.         (void) sprintf(message, "Error %d deleting old console log file.", err);
  145.         Show_error( message );
  146.     }
  147.     g_logfile_refnum = 0;
  148.     err = Create( (StringPtr)*t_str, g_app_wdrefnum, 'dviM', 'TEXT' );
  149.     if (err != noErr)
  150.     {
  151.         (void) sprintf(message, "Error %d creating console log file.", err);
  152.         Show_error( message );
  153.     }
  154.     else
  155.     {
  156.         err = FSOpen( (StringPtr)*t_str, g_app_wdrefnum, &g_logfile_refnum );
  157.         if (err != noErr)
  158.         {
  159.             (void) sprintf(message, "Error %d opening console log file.", err);
  160.             Show_error( message );
  161.         }
  162.     }
  163.     HUnlock( t_str );
  164.     ReleaseResource( t_str );
  165.  
  166.     *status = noErr;
  167.     return the_window;
  168. }
  169.  
  170. /* --------------------------- TD_close_log --------------------------- */
  171. void    TD_close_log( void )
  172. {
  173.     (void) FSClose( g_logfile_refnum );
  174.     (void) FlushVol( nil, g_app_wdrefnum );
  175. }
  176.  
  177.  
  178. /* ------------------------ TD_printf --------------------------- */
  179. void TD_printf( char *format, ... )
  180. {
  181.     va_list        arg_ptr;
  182.     char        str[256];
  183.     int            i;
  184.     register int    amount_to_keep;
  185.     register int    line_len;
  186.     int                max_text;
  187.     TEHandle        the_text;
  188.     ControlHandle    the_bar;
  189.     long            bytes;
  190.     
  191.     va_start( arg_ptr, format );
  192.     i = vsprintf( str, format, arg_ptr ); /* Find string to display. */
  193.     va_end( arg_ptr );
  194.     for (i--; i >= 0; i--)    /* Convert newlines to carriage returns. */
  195.         if (str[i] == '\n')
  196.             str[i] = '\r';
  197.     
  198.     
  199.     line_len = strlen(str);
  200.     the_text = ((TD_peek)g_console_window)->text;
  201.     the_bar = ((WindowPeek)g_console_window)->controlList;
  202.     max_text = ((TD_peek)g_console_window)->max_text;
  203.     
  204.     /*
  205.         Is there enough room in our text block? if not shift the text
  206.         up in the block.
  207.     */
  208.     if ( (**the_text).teLength > max_text - line_len )
  209.     {
  210.         amount_to_keep = ((TD_peek)g_console_window)->min_text;
  211.         if ( amount_to_keep > (max_text - line_len) )
  212.             amount_to_keep = max_text - line_len;
  213.         TESetSelect( 0L, (long)((**the_text).teLength - amount_to_keep),
  214.             the_text );
  215.         TEDelete( the_text );
  216.     }
  217.  
  218.     TESetSelect( (long)(**the_text).teLength, (long)(**the_text).teLength,
  219.         the_text );
  220.     TEInsert( str, (long)line_len, the_text );
  221.     TEPinScroll( 0, -1000, the_text );
  222.     TD_adjust_scrollbar_max( the_text, the_bar );
  223.     SetCtlValue( the_bar, GetCtlMax( the_bar ) );
  224.     
  225.     if (g_logfile_refnum != 0)
  226.     {
  227.         bytes = line_len;
  228.         (void) FSWrite( g_logfile_refnum, &bytes, (Ptr)str );
  229.         (void) FlushVol( nil, g_app_wdrefnum );
  230.     }
  231. }
  232.  
  233. /* ---------------------- TD_resize ----------------------------------- */
  234. void TD_resize( )
  235. {
  236.     register TEHandle    the_text;
  237.     ControlHandle        the_bar;
  238.     Rect                grow_rect;
  239.     
  240.     if ((WindowPtr)thePort == g_console_window)
  241.     {
  242.         the_text = ((TD_peek)g_console_window)->text;
  243.         the_bar = ((WindowPeek)g_console_window)->controlList;
  244.         
  245.         grow_rect = (**the_bar).contrlRect;
  246.         grow_rect.top = grow_rect.bottom;
  247.         grow_rect.bottom += GROW_ICON_SIZE;
  248.         InvalRect( &grow_rect );
  249.  
  250.         (**the_text).viewRect = thePort->portRect;
  251.         (**the_text).viewRect.right -= GROW_ICON_SIZE;
  252.         (**the_text).viewRect.bottom -= TEXT_MARGIN;
  253.         (**the_text).viewRect.top += TEXT_MARGIN;
  254.         (**the_text).destRect = (**the_text).viewRect;
  255.         InsetRect( &(**the_text).destRect, TEXT_MARGIN, 0 );
  256.         TECalText( the_text );
  257.         TD_adjust_scrollbar_max( the_text, the_bar );
  258.         Adjust_text( the_text, the_bar );
  259.         
  260.         MoveControl( the_bar,
  261.             thePort->portRect.right - GROW_ICON_SIZE + 1, -1 );
  262.         SizeControl( the_bar, GROW_ICON_SIZE,
  263.             thePort->portRect.bottom - GROW_ICON_SIZE + 3 );
  264.         grow_rect = (**the_bar).contrlRect;
  265.         grow_rect.top = grow_rect.bottom;
  266.         grow_rect.bottom += GROW_ICON_SIZE;
  267.         InvalRect( &grow_rect );
  268.     }
  269. }
  270.  
  271. /* ---------------------- TD_activate ------------------------ */
  272. void TD_activate( Boolean activate )
  273. {
  274.     Rect    scrollrect;
  275.     ControlHandle    the_bar;
  276.     int        old_hilite, new_hilite;
  277.     TEHandle    the_text;
  278.     
  279.     if (thePort == g_console_window)
  280.     {
  281.         the_bar = ((WindowPeek)g_console_window)->controlList;
  282.         the_text = ((TD_peek)g_console_window)->text;
  283.         if (activate)
  284.             TEActivate( the_text );
  285.         else
  286.             TEDeactivate( the_text );
  287.         scrollrect = (**the_bar).contrlRect;
  288.         old_hilite = (**the_bar).contrlHilite;
  289.         new_hilite = activate? ACTIVE : INACTIVE;
  290.         if (old_hilite != new_hilite)
  291.         {
  292.             HiliteControl( the_bar, new_hilite );
  293.             ValidRect( &scrollrect );
  294.         }
  295.         /*    Under certain circumstances, this routine may be called to
  296.             deactivate the window when it's already inactive.
  297.             HiliteControl does not redraw a control if the hilite
  298.             value doesn't change, so in that case we should not
  299.             validate the scroll bar. 
  300.         */
  301.     }
  302. }
  303.  
  304. /* --------------------- TD_update ---------------------------- */
  305. void TD_update( )
  306. {
  307.     register TEHandle    the_text;
  308.     
  309.     if ((WindowPtr)thePort == g_console_window)
  310.     {
  311.         the_text = ((TD_peek)g_console_window)->text;
  312.         TEUpdate( &(**the_text).viewRect, the_text );
  313.     }
  314. }
  315.  
  316. /* -------------------- TD_click ------------------------------ */
  317. void TD_click( Point where )
  318. {
  319.     Point local_point;
  320.     int        the_part;
  321.     ControlHandle    the_control;
  322.     register TEHandle    the_text;
  323.     
  324.     if ((WindowPtr)thePort == g_console_window)
  325.     {
  326.         the_text = ((TD_peek)g_console_window)->text;
  327.         local_point = where;
  328.         GlobalToLocal( &local_point );
  329.         the_part = FindControl( local_point, thePort, &the_control );
  330.         if (the_part)
  331.             Handle_scroll( the_text, the_part, local_point,
  332.                 ((WindowPeek)g_console_window)->controlList );
  333.         else
  334.             TEClick( local_point, FALSE, the_text );
  335.     }
  336. }
  337.  
  338. #if TD_COPYABLE
  339. /* ------------------------ TD_copy ------------------------------ */
  340. void TD_copy( )
  341. {
  342.     TEHandle    the_text;
  343.     OSErr        err;
  344.     
  345.     if ((WindowPtr)thePort == g_console_window)
  346.     {
  347.         the_text = ((TD_peek)g_console_window)->text;
  348.         TECopy( the_text );
  349.         err = ZeroScrap();
  350.         if (err == noErr)
  351.             err = TEToScrap();
  352.     }
  353. }
  354.  
  355. #else /* not TD_COPYABLE */
  356. void foo( void );
  357. /* ----------------------- High_hook ------------------------------ */
  358. /* 
  359.     The highHook routine is called by TextEdit to highlight the selection
  360.     range.  In this case I want no highlighting.
  361. */
  362. void foo(){
  363.     asm {
  364.         extern High_hook:
  365.         ADDQ.L    #4,SP    /* Throw away the argument, the address of a Rect */
  366.         RTS
  367.     }
  368. }
  369. #endif
  370.  
  371. /* ------------------- TD_adjust_scrollbar_max -------------------------- */
  372. void TD_adjust_scrollbar_max( 
  373.     TEHandle the_text, ControlHandle the_bar )
  374. {
  375.     int        window_height;
  376.     int     lines_above;
  377.     
  378.     window_height = ( (**the_text).viewRect.bottom
  379.         - (**the_text).viewRect.top ) / (**the_text).lineHeight;
  380.     lines_above = (**the_text).nLines - window_height;
  381.     if (lines_above <= 0)
  382.     {
  383.         HiliteControl( the_bar, INACTIVE );
  384.         lines_above = 0;
  385.     }
  386.     else if ( g_console_window == FrontWindow() )
  387.         HiliteControl( the_bar, ACTIVE );
  388.     SetCtlMax( the_bar, lines_above );
  389. }
  390.  
  391. /* ---------------------- Handle_scroll -------------------------------- */
  392. static void Handle_scroll( TEHandle the_text, int the_part, Point where,
  393.     ControlHandle the_bar )
  394. {
  395.     if (the_part == inThumb)
  396.     {
  397.         (void) TrackControl( the_bar, where, nil );
  398.         Adjust_text( the_text, the_bar );
  399.     }
  400.     else
  401.         (void) TrackControl( the_bar, where, (ProcPtr)Scroll_text );
  402. }
  403.  
  404. /* ---------------------- Adjust_text ----------------------------- */
  405. static void Adjust_text( TEHandle the_text, ControlHandle the_bar )
  406. {
  407.     int old_scroll, new_scroll;
  408.     
  409.     old_scroll = (**the_text).viewRect.top - (**the_text).destRect.top;
  410.     new_scroll = GetCtlValue( the_bar ) * (**the_text).lineHeight;
  411.     TEScroll( 0, old_scroll - new_scroll, the_text );
  412. }
  413.  
  414. /* ------------------------ Scroll_text ----------------------------- */
  415. static pascal void Scroll_text( ControlHandle the_bar, int part_code )
  416. {
  417.     int        delta, old_value;
  418.     WindowPtr    the_display;
  419.     TEHandle    the_text;
  420.     
  421.     if (part_code != 0)
  422.     {
  423.         the_display = (**the_bar).contrlOwner;
  424.         the_text = ((TD_peek)the_display)->text;
  425.         
  426.         switch (part_code)
  427.         {
  428.             case inUpButton:
  429.                 delta = -1;
  430.                 break;
  431.             case inDownButton:
  432.                 delta = 1;
  433.                 break;
  434.             case inPageUp:
  435.                 delta = ( (**the_text).viewRect.top
  436.                     - (**the_text).viewRect.bottom )
  437.                     / (**the_text).lineHeight + 1;
  438.                 break;
  439.             case inPageDown:
  440.                 delta = ( (**the_text).viewRect.bottom
  441.                     - (**the_text).viewRect.top )
  442.                     / (**the_text).lineHeight - 1;
  443.                 break;
  444.         }
  445.         old_value = GetCtlValue( the_bar );
  446.         if ( ((delta < 0) && (old_value > 0)) ||
  447.             ((delta > 0) && (old_value < GetCtlMax(the_bar))) )
  448.             SetCtlValue( the_bar, old_value + delta );
  449.         Adjust_text( the_text, the_bar );
  450.     }
  451. }
  452.  
  453. /* ------------------------- Auto_scroll ----------------------------- */
  454. static pascal Boolean Auto_scroll()
  455. {
  456.     Point    mouse_point;
  457.     Rect    view_rect;
  458.     RgnHandle    save_clip;
  459.     WindowPtr    the_display;
  460.     TEHandle    the_text;
  461.     ControlHandle    the_bar;
  462.     
  463.     the_display = FrontWindow();
  464.     the_text = ((TD_peek)the_display)->text;
  465.     the_bar = ((WindowPeek)the_display)->controlList;
  466.     
  467.     save_clip = NewRgn();
  468.     GetClip( save_clip );
  469.     ClipRect( &the_display->portRect );
  470.     GetMouse( &mouse_point );
  471.     view_rect = (**the_text).viewRect;
  472.     if (mouse_point.v < view_rect.top)
  473.         Scroll_text( the_bar, inUpButton );
  474.     else if (mouse_point.v > view_rect.bottom)
  475.         Scroll_text( the_bar, inDownButton );
  476.     SetClip( save_clip );
  477.     DisposeRgn( save_clip );
  478.     return TRUE;
  479. }
  480.